﻿/*   Copyright 2011 Alexander Omelchuk
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 */

using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Runtime.CompilerServices;
using Microsoft.CSharp.RuntimeBinder;

namespace Lisp
{
  public static class Dynamic
  {
    private static CSharpArgumentInfo emptyArgInfo =
      CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null);

    private static Dictionary<ExpressionType, CallSite<Func<CallSite, dynamic, dynamic, object>>> opCallSites
      = new Dictionary<ExpressionType, CallSite<Func<CallSite, dynamic, dynamic, object>>>();

    static Dynamic()
    {
      foreach (ExpressionType type in new[]
      {
        ExpressionType.Add,
        ExpressionType.Subtract,
        ExpressionType.Multiply,
        ExpressionType.Divide,
        ExpressionType.Equal,
        ExpressionType.NotEqual
      })
      {
        opCallSites.Add(
          type,
          CallSite<Func<CallSite, dynamic, dynamic, object>>.Create(
            Binder.BinaryOperation(
              CSharpBinderFlags.None, type, null,
              new[] { emptyArgInfo, emptyArgInfo })));
      }
    }

    public static object ApplyBinaryOp(ExpressionType expressionType, object arg1, object arg2)
    {
      var callsite = opCallSites[expressionType];
      return callsite.Target.Invoke(callsite, arg1, arg2);
    }
  }
}